﻿using System;
using System.Windows.Forms;
using ApplicationLibrary;
using ApplicationLibrary.DBManager;
using ApplicationLibrary.ExtendedControls;
using ApplicationLibrary.SqlConnector;
using Plumber.Accounting.Forms;
using Plumber.Accounting.ModuleData;
using Plumber.Accounting.Reports.DataSet;
using Plumber.Masters.ModuleData;
using System.Collections.Generic;


namespace Plumber.Accounting.Reports
{
    public partial class Balance : ApplicationLibrary.DBManager.ReportForm
    {
        private string Title = string.Empty;
        private DSBalance dsBalance = null;
        private DRMasterType drMasterType;
        private DRMasters drMasters;
        private DRMasterTypeByType drMasterByType;
        private string AdminCode;

        private SortedDictionary<string, Columns> Costi = new SortedDictionary<string, Columns>();
        private SortedDictionary<string, Columns> Ricavi = new SortedDictionary<string, Columns>();
        private SortedDictionary<string, Columns> Attivita = new SortedDictionary<string, Columns>();
        private SortedDictionary<string, Columns> Passivita = new SortedDictionary<string, Columns>();

        public Balance()
        : base(Properties.Resources.FN_Balance)
        {
            InitializeComponent();
        }

        protected override void OnBatchExecute(string reportName)
        {
            if (!LoadData())
            {
                MessageBox.Show(Properties.Resources.Msg_NoDataPeriod, Properties.Resources.Warning, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            SetParameterValue("DataStampa", string.Format("Situazione dal {0} al {1}", ctbFromDate.Text, ctbToDate.Text));

            ShowReport(new RPTBalance(), dsBalance);
            int a = GetPages();
        }

        protected override void OnDisableControlsForRun()
        {
        }

        protected override void OnAttachData()
        {
            ctbFromDate.Today = GlobalInfo.CurrentDate.StartYear();
            ctbToDate.Today   = GlobalInfo.CurrentDate.EndYear();
            drMasterType      = new DRMasterType(DRMasterType.Module.All);
            drMasters         = new DRMasters(false);
            drMasterByType    = new DRMasterTypeByType();
            drMasterByType.Find(MasterTypes.E_Administrator);
            AdminCode         = drMasterByType.GetValue<string>(PL_MasterType.Code);

            dsBalance = new DataSet.DSBalance();
            //AddClickableColumn(PL_JournalEntryDetail.JournalNo);
        }

        protected override void OnBindData()
        {
        }

        private bool LoadData()
        {
            dsBalance.Clear();
            Costi.Clear();
            Ricavi.Clear();
            Attivita.Clear();
            Passivita.Clear();

            QueryBuilder qb = new QueryBuilder(true);
            qb.SetQualified = true;

            qb.AddSelectAll(PL_JournalEntryDetail.Name);
            qb.AddFrom(PL_JournalEntryDetail.Name);
            qb.AddJoin(QueryBuilder.JoinType.INNER, PL_JournalEntry.JournalNo, PL_JournalEntryDetail.JournalNo);
            SqlABParameter pFrom = new SqlABParameter("@p1", PL_JournalEntry.PostingDate);
            SqlABParameter pTo = new SqlABParameter("@p2", PL_JournalEntry.PostingDate);
            qb.AddBetween(PL_JournalEntry.PostingDate, pFrom, pTo);

            pFrom.Value = ctbFromDate.Today;
            pTo.Value   = ctbToDate.Today;

            using (SqlABCommand scc = new SqlABCommand(base.providerType, GlobalInfo.SqlConnection)) {
                scc.CommandText = qb.Query;
                scc.Parameters.Add(pFrom);
                scc.Parameters.Add(pTo);
                SqlABDataReader dr = scc.ExecuteReader();
                while (dr.Read())
                    AddRow(dr);
                dr.Close();
            }

            // Read Previous Period
            if (ctbFromDate.Today.Day == 1 && ctbFromDate.Today.Month == 1 && ckbPrevious.Checked)
            {
                qb.Clear();
                qb.SetQualified = true;

                qb.AddSelectAll(PL_JournalEntryDetail.Name);
                qb.AddSelect(PL_MasterType.AccountType);
                qb.AddFrom(PL_JournalEntryDetail.Name);
                qb.AddJoin(QueryBuilder.JoinType.INNER, PL_JournalEntry.JournalNo, PL_JournalEntryDetail.JournalNo);
                qb.AddJoin(QueryBuilder.JoinType.INNER, PL_MasterType.Code, PL_JournalEntryDetail.Type);
                SqlABParameter pUntil = new SqlABParameter("@p1", PL_JournalEntry.PostingDate);
                qb.AddCompare(PL_JournalEntry.PostingDate, pUntil, "<");
                pUntil.Value = ctbFromDate.Today;

                QueryBuilder qb2 = new QueryBuilder(true);
                qb2.SetQualified = true;
                qb2.AND_OR = "OR";
                qb2.AddCompare<int>(PL_MasterType.AccountType, AccountType.E_Assets.Int());
                qb2.AddCompare<int>(PL_MasterType.AccountType, AccountType.E_Liabilities.Int());

                qb.AddFilter(string.Concat("( ", qb2.Where, " )"));
                using (SqlABCommand scc = new SqlABCommand(base.providerType, GlobalInfo.SqlConnection))
                {
                    scc.CommandText = qb.Query;
                    scc.Parameters.Add(pUntil);
                    SqlABDataReader dr = scc.ExecuteReader();
                    while (dr.Read())
                        AddRow(dr);
                    dr.Close();
                }
            }

            CreateReport();

            return dsBalance.BalanceRows.Rows.Count > 0;
        }

        private void AddRow(SqlABDataReader dr)
        {
            string numb = dr.GetValue<string>(PL_JournalEntryDetail.JournalNo);
            string type = dr.GetValue<string>(PL_JournalEntryDetail.Type);
            string code = dr.GetValue<string>(PL_JournalEntryDetail.Code);
            drMasterType.Find(type);
            string description = string.Empty;
            AccountType accType = drMasterType.GetValue<AccountType>(PL_MasterType.AccountType);
            double From = dr.GetValue<double>(PL_JournalEntryDetail.From);
            double To = dr.GetValue<double>(PL_JournalEntryDetail.To);

            if (rdbLevSubType.Checked && !string.IsNullOrEmpty(code))
            {
                drMasters.Find(type, code);
                if (drMasterType.GetValue<MasterTypes>(PL_MasterType.MasterType) == MasterTypes.E_Condominium)
                {
                    if (ckbAdministrator.Checked)
                    {
                        code = drMasters.GetValue<string>(PL_Masters.Administrator);
                        type = AdminCode;
                        drMasters.Find(type, code);
                        description = drMasters.GetValue<string>(PL_Masters.Description);
                    }
                    else
                        description = drMasters.GetValue<string>(PL_Masters.Address);
                }
                else
                    description = drMasters.GetValue<string>(PL_Masters.Description);
            }
            else
                description = drMasterType.GetValue<string>(PL_MasterType.Description);


            AddColumn(accType, type, code, description, From, To);
        }

        private void CreateReport()
        {
            Columns TotP = new Columns() { From = 0, To = 0 };
            Columns TotE = new Columns() { From = 0, To = 0 };
            int rowL = 0, rowR = 0;
            double totL = 0.0, totR = 0.0;

            if (ckbPatrimon.Checked)
            {
                foreach (KeyValuePair<string, Columns> col in Attivita)
                {
                    if (dsBalance.Aggregator.Rows.Count == 0)
                    {
                        DataSet.DSBalance.AggregatorRow aggregator = dsBalance.Aggregator.NewAggregatorRow();
                        aggregator["Header"] = "P";
                        aggregator["Title"] = "STATO PATRIMONIALE";
                        aggregator["HeadLeft"] = "ATTIVITÀ";
                        aggregator["HeadRight"] = "PASSIVITÀ";
                        dsBalance.Aggregator.Rows.Add(aggregator);
                    }

                    if (col.Value.To > col.Value.From)
                        totL = AddLeft("P", col.Value, ref rowL, totL);
                    else
                        totR = AddRight("P", col.Value, ref rowR, totR);
                }

                foreach (KeyValuePair<string, Columns> col in Passivita)
                {
                    if (dsBalance.Aggregator.Rows.Count == 0)
                    {
                        DataSet.DSBalance.AggregatorRow aggregator = dsBalance.Aggregator.NewAggregatorRow();
                        aggregator["Header"] = "P";
                        aggregator["Title"] = "STATO PATRIMONIALE";
                        aggregator["HeadLeft"] = "ATTIVITÀ";
                        aggregator["HeadRight"] = "PASSIVITÀ";
                        dsBalance.Aggregator.Rows.Add(aggregator);
                    }

                    if (col.Value.From > col.Value.To)
                        totR = AddRight("P", col.Value, ref rowR, totR);
                    else
                        totL = AddLeft("P", col.Value, ref rowL, totL);
                }

                int rowT = Math.Max(rowL, rowR);
                AddEmptyRow("P", ref rowT);

                Columns totLeft = new Columns()
                {
                    Description = "TOTALE ATTIVITÀ",
                    From = totL,
                    To = 0
                };
                AddLeft("P", totLeft, ref rowT, null);
                rowT--;
                Columns totRight = new Columns()
                {
                    Description = "TOTALE PASSIVITÀ",
                    From = 0,
                    To = totR
                };
                AddRight("P", totRight, ref rowT, null);
                rowT++;
                AddEmptyRow("P", ref rowT);
                if (totL > totR)
                {
                    Columns totals = new Columns()
                    {
                        Description = "UTILE",
                        From = totL,
                        To = totR
                    };
                    AddRight("P", totals, ref rowT, null);
                }
                else
                {
                    Columns totals = new Columns()
                    {
                        Description = "PERDITA",
                        From = totL,
                        To = totR
                    };
                    AddLeft("P", totals, ref rowT, null);
                }
            }

            totL = totR = 0;
            if (ckbEconomic.Checked)
            {
                rowL = rowR = dsBalance.BalanceRows.Rows.Count;
                foreach (KeyValuePair<string, Columns> col in Costi)
                {
                    if (dsBalance.Aggregator.Rows.Count == (ckbPatrimon.Checked ? 1 : 0))
                    {
                        DataSet.DSBalance.AggregatorRow aggregator = dsBalance.Aggregator.NewAggregatorRow();
                        aggregator["Header"] = "E";
                        aggregator["Title"] = "CONTO ECONOMICO";
                        aggregator["HeadLeft"] = "COSTI";
                        aggregator["HeadRight"] = "RICAVI";
                        dsBalance.Aggregator.Rows.Add(aggregator);
                    }

                    if (col.Value.To > col.Value.From)
                        totL = AddLeft("E", col.Value, ref rowL, totL);
                    else
                        totR = AddRight("E", col.Value, ref rowR, totR);
                }

                foreach (KeyValuePair<string, Columns> col in Ricavi)
                {
                    if (dsBalance.Aggregator.Rows.Count == (ckbPatrimon.Checked ? 1 : 0))
                    {
                        DataSet.DSBalance.AggregatorRow aggregator = dsBalance.Aggregator.NewAggregatorRow();
                        aggregator["Header"] = "E";
                        aggregator["Title"] = "CONTO ECONOMICO";
                        aggregator["HeadLeft"] = "COSTI";
                        aggregator["HeadRight"] = "RICAVI";
                        dsBalance.Aggregator.Rows.Add(aggregator);
                    }

                    if (col.Value.From > col.Value.To)
                        totR = AddRight("E", col.Value, ref rowR, totR);
                    else
                        totL = AddLeft("E", col.Value, ref rowL, totL);
                }

                int rowT = Math.Max(rowL, rowR);
                AddEmptyRow("E", ref rowT);

                Columns totLeft = new Columns()
                {
                    Description = "TOTALE COSTI",
                    From = totL,
                    To = 0
                };
                AddLeft("E", totLeft, ref rowT, null);
                rowT--;
                Columns totRight = new Columns()
                {
                    Description = "TOTALE RICAVI",
                    From = 0,
                    To = totR
                };
                AddRight("E", totRight, ref rowT, null);
                rowT++;
                AddEmptyRow("E", ref rowT);
                if (totL > totR)
                {
                    Columns totals = new Columns()
                    {
                        Description = "PERDITA",
                        From = totL,
                        To = totR
                    };
                    AddRight("E", totals, ref rowT, null);
                }
                else
                {
                    Columns totals = new Columns()
                    {
                        Description = "UTILE",
                        From = totL,
                        To = totR
                    };
                    AddLeft("E", totals, ref rowT, null);
                }
            }
        }

        private double AddLeft(string aggregator, Columns col, ref int row, double? tot)
        {
            if (Math.Round(Math.Abs(col.To - col.From), 2) != 0)
            {
                DataSet.DSBalance.BalanceRowsRow balanceRow;
                if (dsBalance.BalanceRows.Rows.Count <= row)
                {
                    balanceRow = dsBalance.BalanceRows.NewBalanceRowsRow();
                    balanceRow["Header"] = aggregator;
                    dsBalance.BalanceRows.Rows.Add(balanceRow);
                }
                else
                    balanceRow = dsBalance.BalanceRows[row];

                balanceRow["L_Code"] = col.Code;
                balanceRow["L_Description"] = col.Description;
                balanceRow["L_Value"] = Math.Abs(col.To - col.From);
                row++;
            }

            if (tot != null)
            {
                tot += Math.Abs(col.To - col.From);
                return (double)tot;
            }
            return 0;
        }

        private double AddRight(string aggregator, Columns col, ref int row, double? tot)
        {
            if (Math.Round(Math.Abs(col.To - col.From), 2) != 0)
            {
                DataSet.DSBalance.BalanceRowsRow balanceRow;
                if (dsBalance.BalanceRows.Rows.Count <= row)
                {
                    balanceRow = dsBalance.BalanceRows.NewBalanceRowsRow();
                    balanceRow["Header"] = aggregator;
                    dsBalance.BalanceRows.Rows.Add(balanceRow);
                }
                else
                    balanceRow = dsBalance.BalanceRows[row];

                balanceRow["R_Code"] = col.Code;
                balanceRow["R_Description"] = col.Description;
                balanceRow["R_Value"] = Math.Abs(col.To - col.From);
                row++;
            }

            if (tot != null)
            {
                tot += Math.Abs(col.To - col.From);
                return (double) tot;
            }
            return 0;
        }

        private void AddEmptyRow(string aggregator, ref int row)
        {
            DataSet.DSBalance.BalanceRowsRow balanceRow;
            if (dsBalance.BalanceRows.Rows.Count <= row)
            {
                balanceRow = dsBalance.BalanceRows.NewBalanceRowsRow();
                balanceRow["Header"] = aggregator;
                dsBalance.BalanceRows.Rows.Add(balanceRow);
            }
            else
                balanceRow = dsBalance.BalanceRows[row];

            balanceRow["R_Code"] = "";
            balanceRow["R_Description"] = "";
            balanceRow["R_Value"] = 0;

            balanceRow["L_Code"] = "";
            balanceRow["L_Description"] = "";
            balanceRow["L_Value"] = 0;
            row++;
        }

        protected override EmailArgs SendEmail()
        {
            EmailArgs ea = new EmailArgs();
            ea.Subject = Title;
            ea.Attachment = ExportToPdf(Title);
            return ea;
        }

        private void AddColumn(AccountType accType, string type, string code, string desc, double from, double to)
        {
            string key = rdbLevType.Checked
                            ? type
                            : string.Concat(type, "|", code);

            //string typecode = rdbLevSubType.Checked && !string.IsNullOrEmpty(code)
            //                ? code 
            //                : type;

            string typecode = type;
            switch(accType)
            {
                case AccountType.E_Assets:      //Attività
                    if (Attivita.ContainsKey(key))
                    {
                        Attivita[key].From += from;
                        Attivita[key].To += to;
                    }
                    else
                        Attivita.Add(key, new Columns() { Code = typecode, Description = desc, From = from, To = to });
                    break;
                case AccountType.E_Liabilities:   // Passività
                    if (Passivita.ContainsKey(key))
                    {
                        Passivita[key].From += from;
                        Passivita[key].To += to;
                    }
                    else
                        Passivita.Add(key, new Columns() { Code = typecode, Description = desc, From = from, To = to });
                    break;
                case AccountType.E_Costs:       // Costi
                    if (Costi.ContainsKey(key))
                    {
                        Costi[key].From += from;
                        Costi[key].To += to;
                    }
                    else
                        Costi.Add(key, new Columns() { Code = typecode, Description = desc, From = from, To = to });
                    break;
                case AccountType.E_Revenue:    // Ricavi
                    if (Ricavi.ContainsKey(key))
                    {
                        Ricavi[key].From += from;
                        Ricavi[key].To += to;
                    }
                    else
                        Ricavi.Add(key, new Columns() { Code = typecode, Description = desc, From = from, To = to });
                    break;
            }
        }
    }

    internal class Columns
    {
        public string Code        {get;set;}
        public string Description {get;set;}
        public double From        {get;set;}
        public double To          {get;set;}
    }
}